package dcutils.rpg;

// Import Java JDK Classes
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JOptionPane;

// Import DCUtils Classes
import dcutils.Lambda;
import dcutils.Range;
import dcutils.Range.RangeException;
import dcutils.rpg.env.d2.Coords;

/**
 * @author dca
 */
public class RandomWalker {
   public static void main(String[] args) {
      try {
         final Random rand = new Random();
         final Range<Integer> widthOfMovement = new Range<>(1, 5);
         final Range<Integer> heightOfMovement = new Range<>(1, 5);
         final Coords coords = new Coords(
            1 + rand.nextInt(widthOfMovement.getEnding() - 1),
            1 + rand.nextInt(heightOfMovement.getEnding() - 1)
         ); // x, y

         System.out.printf("Walker is at: %s%n", coords);

         final Lambda<Boolean, AtomicBoolean> task = new Lambda<Boolean, AtomicBoolean>() {
            private void moveVertically() {
               if(rand.nextBoolean()) {
                  moveUp();
               } else {
                  moveDown();
               } // END if/else
            } // END moveVertically

            private void moveUp() {
               if(heightOfMovement.withinRange(coords.second() - 1, true)) {
                  // move up
                  coords.up();
               } else {
                  // At edge; move down instead
                  coords.down();
               } // END if/else
            } // END moveUp

            private void moveDown() {
               if(heightOfMovement.withinRange(coords.second() + 1, true)) {
                  // move down
                  coords.down();
               } else {
                  // At edge; move up instead
                  coords.up();
               } // END if/else
            } // END moveDown

            private void moveHorizontally() {
               if(rand.nextBoolean()) {
                  moveLeft();
               } else {
                  moveRight();
               } // END if/else
            } // END moveHorizontally

            private void moveLeft() {
               if(widthOfMovement.withinRange(coords.first() - 1, true)) {
                  // move left
                  coords.left();
               } else {
                  // At edge; move right instead
                  coords.right();
               } // END if/else
            } // END moveLeft

            private void moveRight() {
               if(widthOfMovement.withinRange(coords.first() + 1, true)) {
                  // move right
                  coords.right();
               } else {
                  // At edge; move left instead
                  coords.left();
               } // END if/else
            } // END moveRight

            private void printBoard() {
               for(int x = widthOfMovement.getBeginning() ; x <= widthOfMovement.getEnding() ; ++x) {
                  for(int y = heightOfMovement.getBeginning() ; y <= heightOfMovement.getEnding() ; ++y) {
                     System.out.printf("[%s]", (coords.first() == x && coords.second() == y ? "X" : " "));
                  } // END loop
                  System.out.println();
               } // END loop
            } // END printBoard

            @Override
            public Boolean apply(AtomicBoolean isTheWalkerAlive) throws IllegalArgumentException {
               if(rand.nextBoolean()) {
                  moveVertically();
               } else {
                  moveHorizontally();
               } // END if/else

               System.out.printf("Walker is at: %s%n", coords);
               printBoard();

               return isTheWalkerAlive.get();
            } // END apply
         }; // END Lambda

         // Setup params
         final AtomicBoolean walkerAlive = new AtomicBoolean(true); // The walker is alive at first
         final long start = 1L;
         final long end = 25L;
         final long freq = 1L;

         // Create the task
         final FutureTask future = FutureTask.createRepeatingTask(task, walkerAlive, false, start, end, freq, TimeUnit.SECONDS);

         // Don't terminate while the future is pending completion.
         while(!future.ended()) {
            final int choice = JOptionPane.showConfirmDialog(
               null, // parentComponent
               "Snipe the walker?", // message
               "Decision", // title
               JOptionPane.YES_NO_OPTION
            );

            if(JOptionPane.YES_OPTION == choice) {
               walkerAlive.set(false);
               TimeUnit.SECONDS.sleep(freq);
            } else {
               TimeUnit.SECONDS.sleep(freq * 5);
            } // END if/else
         } // END loop
      } catch(RangeException rangeExc) {
         System.out.printf("Error in RandomWalker: %s: %s%n", rangeExc.getClass().getSimpleName(), rangeExc.getMessage());
         rangeExc.printStackTrace();
      } catch(InterruptedException interruptExc) {
         System.out.printf("Error in RandomWalker: %s: %s%n", interruptExc.getClass().getSimpleName(), interruptExc.getMessage());
         interruptExc.printStackTrace();
      } // END try/catch
   } // END main
} // END class RandomWalker

